#ifndef __BUFFER_H__
#define __BUFFER_H__

// 本文档实现参考 dpdk mbuf

#define BF_ALIGN(len) (((len) + 63) & ~64)

typedef struct bf_buffer_ 
{
    void *buf_addr; //!< 数据部分起始地址
    union 
    {
        void *userdata;   //!< 用户私有空间起始地址
        uint64_t udata64;
    };
    struct bf_buffer_ *next; //!< 下一个buffer的地址
    uint64_t timestamp; //!< 时间戳 按需使用
    uint32_t data_off; //!< 数据起始偏移
    uint32_t data_len; //!< 当前buffer存放的数据长度
    uint32_t buf_len;  //!< buffer的长度
    uint32_t total_len; //!< 整个buffer链存放的数据长度 仅在第一个buffer中有效
    uint32_t priv_size; //!< 私有空间的大小
    uint16_t nb_segs; //!< buffer链的个数
    uint8_t reserve[2]; //!< 保留
} bf_buffer_t;

/**
 * 获取缓冲区中数据的起始地址的偏移地址
 */
#define bf_buffer_mtod_offset(b, t, o)        \
        ((t)((char *)(b)->buf_addr + (b)->data_off + (o)))

/**
 * 获取缓冲区中数据的起始地址
 */
#define bf_buffer_mtod(b, t) bf_buffer_mtod_offset(b, t, 0)

/**
 * 获取私有空间的起始地址 没有则为NULL
 */
#define bf_buffer_to_priv(b) (b->userdata)

/**
 * 获取所有数据缓冲区存储的数据的长度
 */
#define bf_buffer_total_len(b) ((b)->total_len)

/**
 * 获取当前buffer存储的数据的长度
 */
#define bf_buffer_data_len(b) ((b)->data_len)

/**
 * 数据前预置数据
 *
 * @param  b   缓冲区数据结构
 * @param  len 预置的数据的长度
 *
 * @return     成功返回预置数据的起始地址 失败返回NULL
 */
static inline char *bf_buffer_prepend(bf_buffer_t *b,
                                      uint32_t len)
{
    if (len > b->data_off)
    {
        return NULL;
    }

    b->data_off = (uint32_t)(b->data_off - len);
    b->data_len = (uint32_t)(b->data_len + len);
    b->total_len  = (b->total_len + len);

    return (char *)b->buf_addr + b->data_off;
}

/**
 * 数据后追加数据
 *
 * @param  b   缓冲区数据结构
 * @param  len 缓冲区追加数据的长度
 *
 * @return     成功返回追加数据的起始地址 失败返回NULL
 */
static inline char *bf_buffer_append(bf_buffer_t *b, uint32_t len)
{
    void *tail;
    bf_buffer_t *b_last = b;

    while (b_last->next != NULL)
    {
        b_last = b_last->next;
    }

    uint32_t free_len = b_last->buf_len - b_last->data_off - b_last->data_len;

    if (len > free_len)
    {
        return NULL;
    }

    tail = (char *)b_last->buf_addr + b_last->data_off + b_last->data_len;
    b_last->data_len = (uint32_t)(b_last->data_len + len);
    b->total_len  = (b->total_len + len);

    return (char*) tail;
}

/**
 * 删除缓冲区开始处的数据
 *
 * @param  b   缓冲区数据结构
 * @param  len 待删除数据的长度
 *
 * @return     成功返回删除后的数据的起始地址 失败返回NULL
 */
static inline char *bf_buffer_adj(bf_buffer_t *b, uint32_t len)
{
    if (len > b->data_len)
    {
        return NULL;
    }

    b->data_len = (uint32_t)(b->data_len - len);
    b->data_off = (uint32_t)(b->data_off + len);
    b->total_len = (b->total_len - len);

    return (char *)b->buf_addr + b->data_off;
}

/**
 * 删除缓冲区末尾的数据 删除的数据长度不能超过尾部缓冲区存储的数据长度
 *
 * @param  b   缓冲区数据结构
 * @param  len 待删除的数据长度
 *
 * @return     成功返回0 失败返回-1
 */
static inline int32_t bf_buffer_trim(bf_buffer_t *b, uint32_t len)
{
    bf_buffer_t *b_last = b;

    while (b_last->next != NULL)
    {
        b_last = b_last->next;
    }

    if (len > b_last->data_len)
    {
        return -1;
    }

    b_last->data_len = (uint32_t)(b_last->data_len - len);
    b->total_len  = (b->total_len - len);

    return 0;
}

/**
 * 将两个缓冲区拼接成一个链
 *
 * @param  head buffer链的头
 * @param  tail 待插入buffer链尾部的buffer
 *
 */
static inline void bf_buffer_chain(bf_buffer_t *head,
                                   bf_buffer_t *tail)
{
    bf_buffer_t *cur_tail = head;

    while (cur_tail->next != NULL)
    {
        cur_tail = cur_tail->next;
    }

    cur_tail->next = tail;

    head->nb_segs = (uint32_t)(head->nb_segs + tail->nb_segs);
    head->total_len += tail->total_len;

    /* total_len is only set in the head */
    tail->total_len = 0;
}

/**
 * 申请缓冲区
 *
 * @param  buf_size  缓冲区大小
 * @param  priv_size 缓冲区中私有空间的大小
 *
 * @return           成功返回缓冲区的起始地址 失败返回NULL
 */
static inline bf_buffer_t *bf_buffer_alloc(uint32_t buf_size,
        uint32_t priv_size)
{
    bf_buffer_t *b = NULL;
    uint32_t alloc_size = BF_ALIGN(sizeof(bf_buffer_t)) +
                          BF_ALIGN(priv_size) + BF_ALIGN(buf_size);

    b = calloc(1, alloc_size);
    if (!b)
    {
        return NULL;
    }

    if (priv_size)
    {
        b->userdata = (char *)b + BF_ALIGN(sizeof(bf_buffer_t));
        b->priv_size = priv_size;
    }
    else
    {
        b->userdata = NULL;
        b->priv_size = 0;
    }

    b->buf_addr = (char *)b + BF_ALIGN(sizeof(bf_buffer_t))
                  + BF_ALIGN(priv_size);
    b->data_off = 0;
    b->data_len = 0;
    b->buf_len = buf_size;
    b->nb_segs = 1;
    b->total_len = 0;
    b->next = NULL;
    b->timestamp = 0;

    return b;
}

/**
 * 释放缓冲区
 *
 * @param b 缓冲区数据结构
 */
static inline void bf_buffer_free(bf_buffer_t *b)
{
    bf_buffer_t *b_next;

    while (b != NULL) 
    {
        b_next = b->next;
        free(b);
        b = b_next;
    }
}

/**
 * 将数据写入缓冲区
 *
 * @param  b    缓冲区数据结构
 * @param  data 待写入数据起始地址
 * @param  len  待写入数据的长度
 *
 * @return      成功返回0 失败返回-1
 */
static inline int32_t bf_buffer_write(bf_buffer_t *b,
		uint8_t *data,
		uint32_t len)
{
    char *write_ptr = bf_buffer_append(b, len);
    if (!write_ptr)
    {
        int32_t size = (len > b->buf_len) ? len : b->buf_len;
        bf_buffer_t *temp = bf_buffer_alloc(size, b->priv_size);
        if (!temp)
        {
            return -1;
        }

        bf_buffer_chain(b, temp);
        write_ptr = bf_buffer_append(b, len);
        if (!write_ptr)
        {
            return -1;
        }
    }

    // 写入数据
    memcpy(write_ptr, data, len);

    return 0;
}

#endif

